package com.gk.panda.apis.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dahuatech.hutool.http.Method;
import com.dahuatech.icc.exception.ClientException;
import com.dahuatech.icc.oauth.http.IClient;
import com.dahuatech.icc.oauth.http.IccTokenResponse;
import com.dahuatech.icc.oauth.model.v202010.GeneralRequest;
import com.dahuatech.icc.oauth.model.v202010.GeneralResponse;
import com.gk.panda.apis.Vo.exports.ExportDeviceEcologicalVO;
import com.gk.panda.apis.Vo.exports.ExportDeviceInfraredVO;
import com.gk.panda.apis.Vo.exports.ExportDeviceVideoVO;
import com.gk.panda.apis.config.IccConfig;
import com.gk.panda.apis.dto.imports.ImportDeviceDTO;
import com.gk.panda.apis.entity.DataVisualization.vo.MonitoringEquipmentVo;
import com.gk.panda.apis.entity.deviceManager.bo.DeviceCountGroupByTypeBo;
import com.gk.panda.apis.entity.deviceManager.dto.CloudDirectionDto;
import com.gk.panda.apis.entity.deviceManager.dto.DeviceListDto;
import com.gk.panda.apis.entity.deviceManager.dto.SaveOrChangeDeviceDataDto;
import com.gk.panda.apis.entity.deviceManager.vo.DeviceManagerDetailsVo;
import com.gk.panda.apis.entity.deviceManager.vo.DeviceManagerListVo;
import com.gk.panda.apis.entity.icc.dto.CameraDto;
import com.gk.panda.apis.entity.icc.dto.CloudParamDto;
import com.gk.panda.apis.entity.icc.dto.OperateDto;
import com.gk.panda.apis.entity.icc.dto.VideoLiveDto;
import com.gk.panda.apis.entity.icc.vo.*;
import com.gk.panda.apis.entity.largeScreen.Enum.OrgEnum;
import com.gk.panda.apis.entity.largeScreen.vo.InfraredCameraVo;
import com.gk.panda.apis.entity.largeScreen.vo.VidiconVo;
import com.gk.panda.apis.enums.DeviceManagerModelTypeEnum;
import com.gk.panda.apis.mapper.DeviceManagerMapper;
import com.gk.panda.apis.service.DeviceManagerService;
import com.gk.panda.apis.service.OrgService;
import com.gk.panda.apis.util.ListCopyUtils;
import com.gk.panda.apis.util.excel.ExcelUtils;
import com.gk.panda.commons.constant.Constants;
import com.gk.panda.commons.exception.ServerException;
import com.gk.panda.commons.util.UserUtil;
import com.gk.panda.pojo.DeviceManager;
import com.gk.panda.pojo.Org;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName: DeviceManagerServiceImpl
 * @Description: 设备管理
 * @author: Sir.yang
 * @date: 2022/11/7 18:38
 * @version: 1.0
 **/
@Service
@Slf4j
public class DeviceManagerServiceImpl extends ServiceImpl<DeviceManagerMapper, DeviceManager> implements DeviceManagerService {

    /**
     * 文件地址
     */
    private static final String TEMPLATE_INFRARED_NAME = "红外相机导入模板.xlsx";
    private static final String TEMPLATE_VIDEO_NAME = "摄像机导入模板.xlsx";
    private static final String TEMPLATE_ECOLOGICAL_NAME = "生态设备导入模板.xlsx";
    /**
     * 文件模板后缀
     */
    private static final String FILE_SUFFIX = ".xlsx";

    @Autowired
    private IccConfig iccConfig;

    @Autowired
    private OrgService orgService;

    @Autowired
    private IClient iClient;

    /**
     * @description: 新增
     * @param: [dto]
     * @return: java.lang.Integer
     * @date: 2022/11/7 18:48
     * @version: 1.0
     **/
    @Override
    public Integer saveDeviceData(SaveOrChangeDeviceDataDto dto) throws UnsupportedEncodingException {
        DeviceManager deviceManager = new DeviceManager();
        BeanUtils.copyProperties(dto, deviceManager);
        deviceManager.setProductionDate(DateUtil.parse(dto.getProductionDate()));
        deviceManager.setDeploymentTime(DateUtil.parse(dto.getDeploymentTime()));
        //获取用户信息
        deviceManager.setFkCreate(UserUtil.getCurrentUser());
        deviceManager.setCreateName(UserUtil.getCurrentUserName());
        deviceManager.setCreateTime(new Date());
        return baseMapper.insert(deviceManager);
    }

    /**
     * @description: 修改设备信息
     * @param: [dto]
     * @return: java.lang.Integer
     * @date: 2022/11/7 18:48
     * @version: 1.0
     **/
    @Override
    public Integer changeDeviceData(SaveOrChangeDeviceDataDto dto) throws UnsupportedEncodingException {
        if (null == dto.getDeviceId()) {
            throw new ServerException("设备id不能为空");
        }
        DeviceManager deviceManager = new DeviceManager();
        BeanUtils.copyProperties(dto, deviceManager);
        deviceManager.setProductionDate(DateUtil.parse(dto.getProductionDate()));
        deviceManager.setDeploymentTime(DateUtil.parse(dto.getDeploymentTime()));
        deviceManager.setUpdateName(UserUtil.getCurrentUserName());
        deviceManager.setFkUpdate(UserUtil.getCurrentUser());
        deviceManager.setUpdateTime(new Date());
        return baseMapper.updateById(deviceManager);
    }

    /**
     * @description: 根据设备ID获取设备详情
     * @param: [deviceId]
     * @return: com.gk.panda.apis.entity.deviceManager.vo.DeviceManagerDetailsVo
     * @date: 2022/11/7 18:54
     * @version: 1.0
     **/
    @Override
    public DeviceManagerDetailsVo getDeviceDetailsById(Integer devicdId) {
        DeviceManager deviceManager = baseMapper.selectById(devicdId);
        DeviceManagerDetailsVo vo = new DeviceManagerDetailsVo();
        if (!ObjectUtils.isEmpty(deviceManager)) {
            BeanUtils.copyProperties(deviceManager, vo);
        }
        return vo;
    }

    /**
     * @description: 获取设备列表
     * @param: [dto]
     * @return: com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.gk.panda.apis.entity.deviceManager.vo.DeviceManagerListVo>
     * @date: 2022/11/7 19:00
     * @version: 1.0
     **/
    @Override
    public Page<DeviceManagerListVo> getDevicePage(DeviceListDto dto) {
        Page<DeviceManager> page = new Page<>(dto.getPageNumber(), dto.getPageSize());
        QueryWrapper<DeviceManager> wrapper = new QueryWrapper<>();
//        List<Integer> ids = dto.getFkOrgId();
//        List<Integer> idList = new ArrayList<>();
//        if (ids != null) {
//            ids.forEach(id -> {
//                List<Integer> orgIds = orgService.getPuisneOrgIds(id);
//                idList.addAll(orgIds);
//            });
//            List<Integer> collect = idList.stream().distinct().collect(Collectors.toList());
//            wrapper.in("fk_org_id", collect);
//        }
        wrapper.in(dto.getFkOrgId() != null,"fk_org_id",dto.getFkOrgId());
        wrapper.eq(StringUtils.isNotEmpty(dto.getModelType()),"model_type", dto.getModelType());
        wrapper.in(dto.getModelTypes() != null,"model_type",dto.getModelTypes());
        wrapper.eq("del_flag", Constants.ZERO);
        if (StringUtils.isNotEmpty(dto.getDeviceName())) {
            wrapper.and(queryWrapper -> {
                queryWrapper.like("device_name", dto.getDeviceName())
                        .or().like("device_sn", dto.getDeviceName())
                        .or().like("device_address", dto.getDeviceName());
            });
        }
        wrapper.like(StringUtils.isNotEmpty(dto.getFactoryName()), "factory_name", dto.getFactoryName());
        if (StringUtils.isNotEmpty(dto.getDeploymentStartTime()) && StringUtils.isNotEmpty(dto.getDeploymentEndTime())) {
            wrapper.between("deployment_time",
                    DateUtil.beginOfDay(DateUtil.parse(dto.getDeploymentStartTime())),
                    DateUtil.endOfDay(DateUtil.parse(dto.getDeploymentEndTime())));
        }
        wrapper.in(null != dto.getIfPtz(),"if_ptz", dto.getIfPtz());
        wrapper.in(null != dto.getDeviceStatus(),"device_status", dto.getDeviceStatus());
        wrapper.in(null != dto.getDeviceType(),"device_type", dto.getDeviceType());
        wrapper.eq(StringUtils.isNotEmpty(dto.getRemainingElectricity()),"remaining_electricity", dto.getRemainingElectricity());
        wrapper.orderByDesc("create_time");
        Page<DeviceManager> managerPage = baseMapper.selectPage(page, wrapper);
//        List<DeviceManager> deviceManagers = list(wrapper);
        //转换返回数据
        Page<DeviceManagerListVo> voPage = new Page<>();
        if (!CollectionUtils.isEmpty(managerPage.getRecords())) {
            List<DeviceManagerListVo> vos = managerPage.getRecords().stream().map(device -> {
                DeviceManagerListVo vo = new DeviceManagerListVo();
                BeanUtils.copyProperties(device, vo);
                return vo;
            }).collect(Collectors.toList());
//            int count = vos.size();
            voPage.setRecords(vos);
            voPage.setPages(managerPage.getPages());
            voPage.setCurrent(managerPage.getCurrent());
            voPage.setSize(managerPage.getSize());
            voPage.setTotal(managerPage.getTotal());
        }
        return voPage;
    }

    /**
     * @description: 删除设备信息
     * @param: [devicdId]
     * @return: java.lang.Integer
     * @date: 2022/11/9 15:05
     * @version: 1.0
     **/
    @Override
    @Transactional
    public Integer removeDeviceById(Integer devicdId) throws UnsupportedEncodingException {
        DeviceManager device = new DeviceManager();
        device.setDeviceId(devicdId);
        device.setDelFlag(Constants.ONE);
        device.setUpdateName(UserUtil.getCurrentUserName());
        device.setFkUpdate(UserUtil.getCurrentUser());
        device.setUpdateTime(new Date());
        return baseMapper.updateById(device);
    }

    /**
     * @description: 数据可视化统计数据
     * 获取红外相机，摄像机数量
     * @param: [orgId]
     * @return: com.gk.panda.apis.entity.DataVisualization.vo.MonitoringEquipmentVo
     * @date: 2022/11/11 14:31
     * @version: 1.0
     *
     * @param orgIds*/
    @Override
    public MonitoringEquipmentVo getMonitoringEquipmentCount(List<Integer> orgIds) {
        MonitoringEquipmentVo vo = new MonitoringEquipmentVo();
        List<DeviceCountGroupByTypeBo> bos = baseMapper.getMonitoringEquipmentCount(orgIds);
        if (!CollectionUtils.isEmpty(bos)) {
            for (DeviceCountGroupByTypeBo bo : bos) {
                if(StringUtils.isNotEmpty(bo.getModelType()) && DeviceManagerModelTypeEnum.INFRARED_CAMERA.getCode().equals(bo.getModelType())){
                    //红外相机
                    vo.setCameraNum(bo.getNum());
                }
                if(StringUtils.isNotEmpty(bo.getModelType()) && DeviceManagerModelTypeEnum.VIDEO_CAMERA.getCode().equals(bo.getModelType())){
                    //摄像机
                    vo.setVideoCameraNum(bo.getNum());
                }
            }
        }
        return vo;
    }

    /**
     * @Description: 从icc获取设备列表
     * @version v1.0
     * @author t
     * @date 2022/11/24 11:14
     */
    @Override
    public List<IccDeviceVo> iccDeviceListQuery() {
        List<IccDeviceVo> deviceVoList = new ArrayList<>();
        try {
            String url = iccConfig.getDevicePageUrl() + "?pageNum=1&pageSize=999&searchKey=&sortType=&isOnline=&ownerCode=001&showChildNodeData=1&deviceCategory=";
            GeneralRequest generalRequest = new GeneralRequest(url, Method.GET);
            GeneralResponse response = iClient.doAction(generalRequest, generalRequest.getResponseClass());
            IccMapResultVo iccMapResultVo = JSON.parseObject(response.getResult(), IccMapResultVo.class);
            if(iccMapResultVo.getSuccess()){
                IccResultInfo iccResultInfo = JSON.parseObject(iccMapResultVo.getData(), IccResultInfo.class);
                deviceVoList = iccResultInfo.getPageData();
            }
        } catch (ClientException e) {
            throw new ServerException("调用icc获取设备列表接口失败");
        }
        return deviceVoList;
    }

    /**
     * 在线监控方向控制
     * @param directionDto
     * @return
     */
    @Override
    public int operateDirect(CloudDirectionDto directionDto) {
        IccMapResultVo iccMapResultVo = new IccMapResultVo();
        String deviceSn = directionDto.getDeviceSn();
        QueryWrapper<DeviceManager> wrapper = new QueryWrapper<>();
        wrapper.eq("device_sn",deviceSn).eq("device_status",0)
                .eq("del_flag",0).eq("model_type","video_camera");
        DeviceManager device = this.getOne(wrapper);
        if (device == null) return -1;
        String channelCodes = device.getChannelCodes();
        String[] split = channelCodes.split(",");
        OperateDto operateDto = new OperateDto();
        BeanUtils.copyProperties(directionDto,operateDto);
        operateDto.setChannelId(split[0]);
        CloudParamDto cloudParamDto = new CloudParamDto(operateDto);
        try {
            GeneralRequest generalRequest = new GeneralRequest(iccConfig.getOperateDirectUrl(), Method.POST);
            generalRequest.body(JSONUtil.toJsonStr(cloudParamDto));
            GeneralResponse response = iClient.doAction(generalRequest, generalRequest.getResponseClass());
            iccMapResultVo = JSON.parseObject(response.getResult(), IccMapResultVo.class);
            if (!iccMapResultVo.getCode().equals("1000")) return -2;
        }catch (ClientException e){
            throw new ServerException("调用在线监控方向控制接口失败");
        }
        return 0;
    }

    /**
     * ICC获取野保相机图片视频列表
     * @param cameraDto
     * @return
     */
    @Override
    public List<VideoListVo> cameraList(CameraDto cameraDto) {
        List<VideoListVo> videoListVos = new ArrayList<>();
        try {
            String url = iccConfig.getCameraVideoAndPicUrl();
            IccTokenResponse.IccToken token = iClient.getAccessToken();
            GeneralRequest generalRequest = new GeneralRequest(url, Method.POST);
            generalRequest.body(JSON.toJSONString(cameraDto));
            GeneralResponse response = iClient.doAction(generalRequest, generalRequest.getResponseClass());
            String result = response.getResult();
            IccMapResultVo iccMapResultVo = JSON.parseObject(response.getResult(), IccMapResultVo.class);
            if(iccMapResultVo.getSuccess()){
                VideoListResultInfo info = JSON.parseObject(iccMapResultVo.getData(), VideoListResultInfo.class);
                videoListVos = info.getPageList();
            }

        } catch (Exception e) {
            throw new ServerException("调用ICC获取野保相机图片视频列表接口失败");
        }
        return videoListVos;
    }

    /**
     * 保存或更新ICC数据
     * @return
     */
    @Override
    public String saveDeviceFromIcc() {
        List<IccDeviceVo> iccDeviceVos = iccDeviceListQuery();
        List<DeviceManager> updateList = new ArrayList<>();
        List<DeviceManager> saveList = new ArrayList<>();
        for (IccDeviceVo iccDeviceVo : iccDeviceVos) {
            DeviceManager device = getOne(Wrappers.<DeviceManager>lambdaQuery().eq(DeviceManager::getDeviceSn, iccDeviceVo.getDeviceCode()));
            if (device != null) {
                device.setDeviceStatus(iccDeviceVo.getIsOnline() == 0 ? 1 : 0);
                updateList.add(device);
            } else {
                DeviceManager deviceIcc = new DeviceManager();
                deviceIcc.setOrgName("大熊猫国家公园成都管理分局");
                deviceIcc.setFkOrgId(1);
                deviceIcc.setDeviceSn(iccDeviceVo.getDeviceCode());
                deviceIcc.setDeviceStatus( iccDeviceVo.getIsOnline() ==1 ? 0:1);
                deviceIcc.setDeviceName(iccDeviceVo.getDeviceName());
                if (iccDeviceVo.getDeviceCategory().equals("52")) {
                    deviceIcc.setModelType("infrared_camera");
                } else if(iccDeviceVo.getDeviceCategory().equals("1")) {
                    deviceIcc.setModelType("video_camera");
                }
                if(!CollectionUtils.isEmpty(iccDeviceVo.getUnits())){
                    List<UnitVo> units = iccDeviceVo.getUnits();
                    List<String> str = new ArrayList<>();
                    for (UnitVo unit : units) {
                        List<ChannelsVo> channels = unit.getChannels();
                        List<String> channelCodes = channels.stream().map(channelsVo ->
                                channelsVo.getChannelCode()).collect(Collectors.toList());
                        str.addAll(channelCodes);
                    }
                    deviceIcc.setChannelCodes(StringUtils.join(str,","));
                }
                //获取用户信息
                deviceIcc.setFkCreate("admin");
                deviceIcc.setCreateName("admin");
                deviceIcc.setCreateTime(new Date());
                deviceIcc.setSourceType(Constants.SOURCE_TYPE);
                saveList.add(deviceIcc);
            }
        }
        updateBatchById(updateList);
        saveBatch(saveList);
        return "success";
    }

    /**
     * 获取大华Icc红外相机设备列表（设备编号、设备地址、所属机构）
     * @return
     */
    @Override
    public List<DeviceManager> getIccDeviceSn() {
        QueryWrapper<DeviceManager> wrapper = new QueryWrapper<>();
        wrapper.select("device_sn","device_address","fk_org_id").eq("source_type","大华")
        .eq("model_type","infrared_camera");
        return this.list(wrapper);
    }

    /**
     * 更新电量
     * @param device
     */
    @Override
    public void updatePower(DeviceManager device) {
        if (device.getRemainingElectricity() != null) {
            UpdateWrapper<DeviceManager> wrapper = new UpdateWrapper<>();
            wrapper.set("remaining_electricity",device.getRemainingElectricity());
            wrapper.eq("device_sn",device.getDeviceSn());
            this.update(wrapper);
        }
    }

    /**
     * icc摄像机设备根据设备编号获取摄像机实时流
     * @param deviceSn
     * @return
     */
    @Override
    public String getVideoLiveStream(String deviceSn) {
        QueryWrapper<DeviceManager> wrapper = new QueryWrapper<>();
        wrapper.eq("device_sn",deviceSn);
        DeviceManager device = this.getOne(wrapper);
        String channelCodesData = device.getChannelCodes();
        String[] channelCodes = channelCodesData.split(",");
        String channelCode = channelCodes[0];
        Map<String,String> data = new HashMap<>();
        data.put("channelId",channelCode);
        data.put("streamType","2");
        data.put("type","hls");
        VideoLiveDto dto = new VideoLiveDto();
        dto.setData(data);
        try {
            String url = iccConfig.getVideoLiveUrl();
            GeneralRequest generalRequest = new GeneralRequest(url, Method.POST);
            generalRequest.body(JSON.toJSONString(dto));
            GeneralResponse response = iClient.doAction(generalRequest, generalRequest.getResponseClass());
            IccMapResultVo iccMapResultVo = JSON.parseObject(response.getResult(), IccMapResultVo.class);
            if(iccMapResultVo.getCode().equals("1000")){
                DeviceLiveVo info = JSON.parseObject(iccMapResultVo.getData(), DeviceLiveVo.class);
                return info.getUrl();
            }

        } catch (Exception e) {
            throw new ServerException("调用ICC获取摄像机实时流接口失败");
        }
        return null;
    }

    /**
     * 大屏根据机构id获取自身及下属机构摄像机信息
     * @param orgId
     * @return
     */
    @Override
    public VidiconVo getVidiconByOrgId(Integer orgId) {
        VidiconVo vidiconVo = new VidiconVo();
        if (orgId == null) orgId = OrgEnum.CHENGDU.getOrgId();
        List<Integer> orgIds = orgService.getPuisneOrgIds(orgId);
        QueryWrapper<DeviceManager> wrapper = new QueryWrapper<>();
        wrapper.in("fk_org_id",orgIds).eq("model_type","video_camera")
                .eq("del_flag",0);
        long count = this.count(wrapper);
        wrapper.clear();
        wrapper.in("fk_org_id",orgIds).eq("model_type","video_camera")
                .eq("del_flag",0).eq("device_status",0);
        long normalNum = this.count(wrapper);
        vidiconVo.setCount(count);
        vidiconVo.setNormalNum(normalNum);
        vidiconVo.setUnusualNum(count-normalNum);
        return vidiconVo;
    }

    /**
     * 大屏获取红外相机信息
     * @return
     */
    @Override
    public List<InfraredCameraVo> getInfraredCamera() {
        List<InfraredCameraVo> vos = new ArrayList<>();
        OrgEnum[] orgEnums = OrgEnum.values();
        for (OrgEnum orgEnum : orgEnums) {
            vos.add(getInfraredCameraByOrgId(orgEnum.getOrgId()));
        }
        return vos;
    }

    /**
     * 根据机构id获取该机构及下属机构红外相机数据
     * @param orgId
     * @return
     */
    private InfraredCameraVo getInfraredCameraByOrgId(Integer orgId) {
        List<Integer> orgIds = orgService.getPuisneOrgIds(orgId);
        QueryWrapper<DeviceManager> wrapper = new QueryWrapper<>();
        wrapper.in("fk_org_id",orgIds).eq("model_type","infrared_camera")
                .eq("del_flag",0);
        long count = this.count(wrapper);
        wrapper.clear();
        wrapper.in("fk_org_id",orgIds).eq("model_type","infrared_camera")
                .eq("del_flag",0).gt("create_time","2022-09-01 00:00:00");
        long newNum = this.count(wrapper);
        InfraredCameraVo vo = new InfraredCameraVo();
        vo.setAreaName(OrgEnum.getNameByOrgId(orgId));
        vo.setCameraCount(count);
        vo.setNewNum(newNum);
        vo.setOldNum(count - newNum);
        return vo;
    }

    /**
     * 根据设备编号获取设备设备详情
     * @param deviceSn
     * @return
     */
    @Override
    public DeviceManager getDeviceBySn(String deviceSn) {
        QueryWrapper<DeviceManager> wrapper = new QueryWrapper<>();
        wrapper.eq("device_sn",deviceSn);
        return this.getOne(wrapper);
    }

    /**
     * 根据机构id获取自身及下属机构设备编号列表
     * @param orgId
     * @return
     */
    @Override
    public List<String> getDeviceSnListByOrgId(Integer orgId) {
        List<Integer> orgIds = orgService.getPuisneOrgIds(orgId);
        return this.baseMapper.getDeviceSnListByOrgId(orgIds);
    }

    /**
     * 下载红外相机导入模板
     *
     * @param response P
     */
    @Override
    public void getInfraredTemplate(HttpServletResponse response) {
        String exception = "红外相机导入模板获取异常！";
        XSSFWorkbook workbook = getWorkbook(exception, TEMPLATE_INFRARED_NAME);
        XSSFSheet sheet = workbook.getSheetAt(0);
        // 所属机构
        List<Org> orgs = orgService.list();
        String[] names = orgs.stream().map(Org::getName).toArray(String[]::new);
        ExcelUtils.setDropDownBox(sheet, 1, 0, 65535, 0, names, workbook, "机构");

        // 设备状态
        String[] deviceStatus = {"正常", "异常"};
        ExcelUtils.setDropDownBox(1, 65535, 8, 8, sheet, deviceStatus);

        // 生成文件
        String downloadFileName = "红外相机信息" + FILE_SUFFIX;
        ExcelUtils.download(downloadFileName, workbook, response);
    }

    /**
     * 下载摄像机导入模板
     *
     * @param response P
     */
    @Override
    public void getVideoTemplate(HttpServletResponse response) {
        String exception = "摄像机导入模板获取异常！";
        XSSFWorkbook workbook = getWorkbook(exception, TEMPLATE_VIDEO_NAME);
        XSSFSheet sheet = workbook.getSheetAt(0);
        // 所属机构
        List<Org> orgs = orgService.list();
        String[] names = orgs.stream().map(Org::getName).toArray(String[]::new);
        ExcelUtils.setDropDownBox(sheet, 1, 0, 65535, 0, names, workbook, "机构");
        // 是否球机
        String[] ifPtz = {"是", "否"};
        ExcelUtils.setDropDownBox(1, 65535, 3, 3, sheet, ifPtz);
        // 设备类型
        String[] deviceType = {"卡口", "慢直播", "动物监测"};
        ExcelUtils.setDropDownBox(1, 65535, 4, 4, sheet, deviceType);
        // 设备状态
        String[] deviceStatus = {"正常", "异常"};
        ExcelUtils.setDropDownBox(1, 65535, 9, 9, sheet, deviceStatus);

        // 生成文件
        String downloadFileName = "摄像机信息" + FILE_SUFFIX;
        ExcelUtils.download(downloadFileName, workbook, response);
    }

    @Override
    public List<String> getLiveVideo() {
        return baseMapper.getLiveVideo();
    }

    /**
     * 下载生态设备导入模板
     *
     * @param response P
     */
    @Override
    public void getEcologicalTemplate(HttpServletResponse response) {
        String exception = "生态设备导入模板获取异常！";
        XSSFWorkbook workbook = getWorkbook(exception, TEMPLATE_ECOLOGICAL_NAME);
        XSSFSheet sheet = workbook.getSheetAt(0);
        // 所属机构
        List<Org> orgs = orgService.list();
        String[] names = orgs.stream().map(Org::getName).toArray(String[]::new);
        ExcelUtils.setDropDownBox(sheet, 1, 0, 65535, 0, names, workbook, "机构");
        // 设备状态
        String[] deviceStatus = {"正常", "异常"};
        ExcelUtils.setDropDownBox(1, 65535, 7, 7, sheet, deviceStatus);

        // 生成文件
        String downloadFileName = "生态设备信息" + FILE_SUFFIX;
        ExcelUtils.download(downloadFileName, workbook, response);
    }

    /**
     * 批量导入红外相机信息
     *
     * @param file P
     * @return R
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importInfrared(MultipartFile file) throws UnsupportedEncodingException {
        InputStream inputStream;
        List<ImportDeviceDTO> resultList;
        try {
            inputStream = file.getInputStream();
            // 选择Sheet,params默认选择第一个sheet
            ImportParams params = new ImportParams();
            // 读取第几个sheet
            params.setStartSheetIndex(0);
            // 每次读取几个sheet
            params.setSheetNum(1);
            // titleRows表示的是表格标题行数，如果没有就是0，如果有一个标题就是1，如果是两个标题就2
            params.setTitleRows(0);
            // 头部占几行
            params.setHeadRows(1);
            resultList = ExcelImportUtil.importExcel(inputStream, ImportDeviceDTO.class, params);
        } catch (Exception e) {
            e.printStackTrace();
            return "failed";
        }
        if (CollectionUtils.isEmpty(resultList)) {
            return "导入数据为空，请检查填入数据！";
        }
        String currentUser = UserUtil.getCurrentUser();
        String currentUserName = UserUtil.getCurrentUserName();
        // 通过机构名称获取机构id
        List<String> names = resultList.stream().map(ImportDeviceDTO::getOrgName).collect(Collectors.toList());
        List<Org> orgList = orgService.list(Wrappers.<Org>lambdaQuery().in(Org::getName, names));
        resultList.forEach(k -> {
            for (Org v : orgList) {
                if (v.getName().equals(k.getOrgName())) {
                    k.setFkOrgId(v.getId());
                }
            }
            if (StringUtils.isNotBlank(k.getDeviceStatusName())) {
                // 因为只有两种状态，所以没有写枚举，如果填写其他状态统统是“异常”
                Integer deviceStatus = "正常".equals(k.getDeviceStatusName()) ? 0 : 1;
                k.setDeviceStatus(deviceStatus);
            }
            k.setModelType(DeviceManagerModelTypeEnum.INFRARED_CAMERA.getCode());
            // 用户信息
            k.setFkCreate(currentUser);
            k.setCreateName(currentUserName);
            k.setCreateTime(new Date());
        });
        List<DeviceManager> deviceManagers = ListCopyUtils.copyListProperties(resultList, DeviceManager::new);
        //校验导入部分是否有重复编号
        List<String> deviceSns = deviceManagers.stream().map(DeviceManager::getDeviceSn).collect(Collectors.toList());
        Set<String> set = new HashSet<>();
        List<String> collect = deviceSns.stream().filter(x -> !set.add(x)).collect(Collectors.toList());
        if (collect.size() > 0) {
            return "表格有重复编号：" + StringUtils.join(collect,",");
        }
        //校验导入部分和数据库是否有重复编号
        QueryWrapper<DeviceManager> wrapper = new QueryWrapper<>();
        wrapper.in("device_sn",deviceSns);
        wrapper.eq("del_flag",Constants.ZERO);
        List<DeviceManager> list = list(wrapper);
        if (list != null && list.size() > 0) {
            return "与已有编号重复：" + StringUtils.join(list.stream().map(DeviceManager::getDeviceSn).collect(Collectors.toList()),",");
        }
        //导入
        saveBatch(deviceManagers);
        return "success";
    }

    /**
     * 批量导入摄像机信息
     *
     * @param file P
     * @return R
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importVideo(MultipartFile file) throws UnsupportedEncodingException {
        InputStream inputStream;
        List<ImportDeviceDTO> resultList;
        try {
            inputStream = file.getInputStream();
            ImportParams params = new ImportParams();
            params.setStartSheetIndex(0);
            params.setSheetNum(1);
            params.setTitleRows(0);
            params.setHeadRows(1);
            resultList = ExcelImportUtil.importExcel(inputStream, ImportDeviceDTO.class, params);
        } catch (Exception e) {
            e.printStackTrace();
            return "failed";
        }
        if (CollectionUtils.isEmpty(resultList)) {
            return "导入数据为空，请检查填入数据！";
        }
        String currentUser = UserUtil.getCurrentUser();
        String currentUserName = UserUtil.getCurrentUserName();
        // 通过机构名称获取机构id
        List<String> names = resultList.stream().map(ImportDeviceDTO::getOrgName).collect(Collectors.toList());
        List<Org> orgList = orgService.list(Wrappers.<Org>lambdaQuery().in(Org::getName, names));
        resultList.forEach(k -> {
            for (Org v : orgList) {
                if (v.getName().equals(k.getOrgName())) {
                    k.setFkOrgId(v.getId());
                }
            }
            if (StringUtils.isNotBlank(k.getDeviceStatusName())) {
                // 因为只有两种状态，所以没有写枚举，如果填写其他状态统统是“异常”
                Integer deviceStatus = "正常".equals(k.getDeviceStatusName()) ? 0 : 1;
                k.setDeviceStatus(deviceStatus);
            }
            if (StringUtils.isNotBlank(k.getIfPtzName())) {
                Integer ifPtz = "是".equals(k.getIfPtzName()) ? 0 : 1;
                k.setIfPtz(ifPtz);
            }
            k.setModelType(DeviceManagerModelTypeEnum.VIDEO_CAMERA.getCode());
            // 用户信息
            k.setFkCreate(currentUser);
            k.setCreateName(currentUserName);
            k.setCreateTime(new Date());
        });
        List<DeviceManager> deviceManagers = ListCopyUtils.copyListProperties(resultList, DeviceManager::new);
        //校验导入部分是否有重复编号
        List<String> deviceSns = deviceManagers.stream().map(DeviceManager::getDeviceSn).collect(Collectors.toList());
        Set<String> set = new HashSet<>();
        List<String> collect = deviceSns.stream().filter(x -> !set.add(x)).collect(Collectors.toList());
        if (collect.size() > 0) {
            return "表格中有重复编号：" + StringUtils.join(collect,",");
        }
        //校验导入部分和数据库是否有重复编号
        QueryWrapper<DeviceManager> wrapper = new QueryWrapper<>();
        wrapper.in("device_sn",deviceSns);
        wrapper.eq("del_flag",Constants.ZERO);
        List<DeviceManager> list = list(wrapper);
        if (list != null && list.size() > 0) {
            return "与已有编号重复：" + StringUtils.join(list.stream().map(DeviceManager::getDeviceSn).collect(Collectors.toList()),",");
        }
        //导入
        saveBatch(deviceManagers);
        return "success";
    }

    /**
     * 批量导入生态设备信息
     *
     * @param file P
     * @return R
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importEcological(MultipartFile file) throws UnsupportedEncodingException {
        InputStream inputStream;
        List<ImportDeviceDTO> resultList;
        try {
            inputStream = file.getInputStream();
            ImportParams params = new ImportParams();
            params.setStartSheetIndex(0);
            params.setSheetNum(1);
            params.setTitleRows(0);
            params.setHeadRows(1);
            resultList = ExcelImportUtil.importExcel(inputStream, ImportDeviceDTO.class, params);
        } catch (Exception e) {
            e.printStackTrace();
            return "failed";
        }
        if (CollectionUtils.isEmpty(resultList)) {
            return "导入数据为空，请检查填入数据！";
        }
        String currentUser = UserUtil.getCurrentUser();
        String currentUserName = UserUtil.getCurrentUserName();
        // 通过机构名称获取机构id
        List<String> names = resultList.stream().map(ImportDeviceDTO::getOrgName).collect(Collectors.toList());
        List<Org> orgList = orgService.list(Wrappers.<Org>lambdaQuery().in(Org::getName, names));
        resultList.forEach(k -> {
            for (Org v : orgList) {
                if (v.getName().equals(k.getOrgName())) {
                    k.setFkOrgId(v.getId());
                }
            }
            if (StringUtils.isNotBlank(k.getDeviceStatusName())) {
                Integer deviceStatus = "正常".equals(k.getDeviceStatusName()) ? 0 : 1;
                k.setDeviceStatus(deviceStatus);
            }
            k.setModelType(DeviceManagerModelTypeEnum.ECOLOGICAL_EQUIPMENT.getCode());
            // 用户信息
            k.setFkCreate(currentUser);
            k.setCreateName(currentUserName);
            k.setCreateTime(new Date());
        });
        List<DeviceManager> deviceManagers = ListCopyUtils.copyListProperties(resultList, DeviceManager::new);
        //校验导入部分是否有重复编号
        List<String> deviceSns = deviceManagers.stream().map(DeviceManager::getDeviceSn).collect(Collectors.toList());
        Set<String> set = new HashSet<>();
        List<String> collect = deviceSns.stream().filter(x -> !set.add(x)).collect(Collectors.toList());
        if (collect.size() > 0) {
            return "表格有重复编号：" + StringUtils.join(collect,",");
        }
        //校验导入部分和数据库是否有重复编号
        QueryWrapper<DeviceManager> wrapper = new QueryWrapper<>();
        wrapper.in("device_sn",deviceSns);
        wrapper.eq("del_flag",Constants.ZERO);
        List<DeviceManager> list = list(wrapper);
        if (list != null && list.size() > 0) {
            return "与已有编号重复：" + StringUtils.join(list.stream().map(DeviceManager::getDeviceSn).collect(Collectors.toList()),",");
        }
        //导入
        saveBatch(deviceManagers);
        return "success";
    }

    /**
     * 批量导出红外相机信息
     *
     * @param response P
     */
    @Override
    public void exportInfrared(HttpServletResponse response) {
        // 查询全部数据
        List<DeviceManager> deviceManagers = list(Wrappers.<DeviceManager>lambdaQuery()
                .eq(DeviceManager::getDelFlag, Constants.ZERO)
                .eq(DeviceManager::getModelType, DeviceManagerModelTypeEnum.INFRARED_CAMERA.getCode())
                .orderByDesc(DeviceManager::getCreateTime));
        if (CollectionUtils.isEmpty(deviceManagers)) {
            throw new ServerException("暂无数据导出！");
        }
        List<ExportDeviceInfraredVO> vos = ListCopyUtils.copyListProperties(deviceManagers, ExportDeviceInfraredVO::new);
        vos.forEach(k -> {
            if (k.getDeviceStatus() != null) {
                String name = k.getDeviceStatus().equals(0) ? "正常" : "异常";
                k.setDeviceStatusName(name);
            }
        });
        // 导出
        ExportParams params = new ExportParams();
        params.setSheetName("红外相机信息");
        params.setHeight((short) 15);
        Workbook workbook = ExcelExportUtil.exportBigExcel(params, ExportDeviceInfraredVO.class, vos);
        ExcelExportUtil.closeExportBigExcel();
        // 生成文件
        String downloadFileName = "红外相机导出" + FILE_SUFFIX;
        ExcelUtils.download(downloadFileName, workbook, response);
    }

    /**
     * 批量导出摄像机信息
     *
     * @param response P
     */
    @Override
    public void exportVideo(HttpServletResponse response) {
        // 查询全部数据
        List<DeviceManager> deviceManagers = list(Wrappers.<DeviceManager>lambdaQuery()
                .eq(DeviceManager::getDelFlag, Constants.ZERO)
                .eq(DeviceManager::getModelType, DeviceManagerModelTypeEnum.VIDEO_CAMERA.getCode())
                .orderByDesc(DeviceManager::getCreateTime));
        if (CollectionUtils.isEmpty(deviceManagers)) {
            throw new ServerException("暂无数据导出！");
        }
        List<ExportDeviceVideoVO> vos = ListCopyUtils.copyListProperties(deviceManagers, ExportDeviceVideoVO::new);
        vos.forEach(k -> {
            if (k.getDeviceStatus() != null) {
                String name = k.getDeviceStatus().equals(0) ? "正常" : "异常";
                k.setDeviceStatusName(name);
            }
            if (k.getIfPtz() != null) {
                String name = k.getIfPtz().equals(0) ? "是" : "否";
                k.setIfPtzName(name);
            }
        });
        // 导出
        ExportParams params = new ExportParams();
        params.setSheetName("摄像机信息");
        params.setHeight((short) 15);
        Workbook workbook = ExcelExportUtil.exportBigExcel(params, ExportDeviceVideoVO.class, vos);
        ExcelExportUtil.closeExportBigExcel();
        // 生成文件
        String downloadFileName = "摄像机导出" + FILE_SUFFIX;
        ExcelUtils.download(downloadFileName, workbook, response);
    }

    /**
     * 批量导出生态设备信息
     *
     * @param response P
     */
    @Override
    public void exportEcological(HttpServletResponse response) {
        // 查询全部数据
        List<DeviceManager> deviceManagers = list(Wrappers.<DeviceManager>lambdaQuery()
                .eq(DeviceManager::getDelFlag, Constants.ZERO)
                .eq(DeviceManager::getModelType, DeviceManagerModelTypeEnum.ECOLOGICAL_EQUIPMENT.getCode())
                .orderByDesc(DeviceManager::getCreateTime));
        if (CollectionUtils.isEmpty(deviceManagers)) {
            throw new ServerException("暂无数据导出！");
        }
        List<ExportDeviceEcologicalVO> vos = ListCopyUtils.copyListProperties(deviceManagers, ExportDeviceEcologicalVO::new);
        vos.forEach(k -> {
            if (k.getDeviceStatus() != null) {
                String name = k.getDeviceStatus().equals(0) ? "正常" : "异常";
                k.setDeviceStatusName(name);
            }
        });
        // 导出
        ExportParams params = new ExportParams();
        params.setSheetName("生态设备信息");
        params.setHeight((short) 15);
        Workbook workbook = ExcelExportUtil.exportBigExcel(params, ExportDeviceEcologicalVO.class, vos);
        ExcelExportUtil.closeExportBigExcel();
        // 生成文件
        String downloadFileName = "生态设备导出" + FILE_SUFFIX;
        ExcelUtils.download(downloadFileName, workbook, response);
    }

    /**
     * 根据当前登录用户获取所属机构及下属机构红外相机列表
     * @return
     */
    @Override
    public List<DeviceManager> infraredCameraListByCurrentUser() {
        int orgId = UserUtil.getCurrentUserOrgId();
        List<Integer> orgIds = orgService.getPuisneOrgIds(orgId);
        return list(Wrappers.<DeviceManager>lambdaQuery().in(DeviceManager::getFkOrgId,orgIds)
                .eq(DeviceManager::getModelType,"infrared_camera")
                .eq(DeviceManager::getDelFlag,0));
    }

    @Override
    public List<DeviceManager> getChenDeviceSn() {
        QueryWrapper<DeviceManager> wrapper = new QueryWrapper<>();
        wrapper.eq("source_type","陈博士")
                .eq("model_type","infrared_camera");
        return this.list(wrapper);
    }

    /**
     * 查询是否存在该设备编码的数据
     * @param deviceCode
     * @return
     */
    public Boolean getDeviceByCode(String deviceCode){
        Boolean flag = false;
        QueryWrapper<DeviceManager> wrapper = new QueryWrapper<>();
        wrapper.eq("device_sn", deviceCode);
        List<DeviceManager> deviceIccs = this.list(wrapper);
        if(!CollectionUtils.isEmpty(deviceIccs)){
            flag = true;
        }
        return flag;
    }

    /**
     * 获取workbook
     *
     * @return XSSFWorkbook
     */
    private XSSFWorkbook getWorkbook(String exception, String fileName) {
        InputStream inputStream;
        XSSFWorkbook workbook;
        try {
            ClassPathResource classPathResource = new ClassPathResource("excels/" + fileName);
            inputStream = classPathResource.getInputStream();
            workbook = new XSSFWorkbook(inputStream);
        } catch (IOException e) {
            throw new ServerException(exception);
        }
        return workbook;
    }


}
